package com.carrental.integration.service.impl;

import com.carrental.integration.config.MinioConfig;
import com.carrental.integration.service.FileService;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * MinIO文件服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MinioFileServiceImpl implements FileService {

    private final MinioClient minioClient;
    private final MinioConfig minioConfig;

    @Override
    public String uploadFile(MultipartFile file) {
        try {
            String fileName = generateFileName(file.getOriginalFilename());
            return uploadFile(file.getInputStream(), fileName, file.getContentType());
        } catch (Exception e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("上传文件失败", e);
        }
    }

    @Override
    public List<String> uploadFiles(List<MultipartFile> files) {
        return files.stream()
                .map(this::uploadFile)
                .collect(Collectors.toList());
    }

    @Override
    public String uploadFile(InputStream inputStream, String fileName, String contentType) {
        try {
            String objectName = minioConfig.getFilePrefix() + fileName;

            // 上传文件
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .stream(inputStream, inputStream.available(), -1)
                    .contentType(contentType)
                    .build());

            // 返回文件访问URL
            return getFileUrl(objectName);
        } catch (Exception e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("上传文件失败", e);
        }
    }

    @Override
    public boolean deleteFile(String fileUrl) {
        try {
            // 从URL中提取对象名称
            String objectName = extractObjectNameFromUrl(fileUrl);

            // 删除文件
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .build());

            return true;
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public String getFileUrl(String objectName) {
        try {
            // 由于桶已设置为公共可读，直接返回URL而不使用预签名URL
            return minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/" + objectName;

            // 如果需要预签名URL，可以使用以下代码
            /*
             * return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
             * .bucket(minioConfig.getBucketName())
             * .object(objectName)
             * .method(Method.GET)
             * .expiry(minioConfig.getUrlExpiry(), TimeUnit.SECONDS)
             * .build());
             */
        } catch (Exception e) {
            log.error("获取文件URL失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取文件URL失败", e);
        }
    }

    /**
     * 批量删除文件
     *
     * @param fileUrls 文件URL列表
     * @return 删除失败的文件列表
     */
    public List<String> deleteFiles(List<String> fileUrls) {
        try {
            List<DeleteObject> objects = fileUrls.stream()
                    .map(this::extractObjectNameFromUrl)
                    .map(DeleteObject::new)
                    .collect(Collectors.toList());

            // 执行批量删除
            Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .objects(objects)
                    .build());

            // 收集删除失败的文件
            List<String> failedFiles = new ArrayList<>();
            for (Result<DeleteError> result : results) {
                DeleteError error = result.get();
                failedFiles.add(error.objectName());
                log.error("删除文件失败: {}, 错误: {}", error.objectName(), error.message());
            }

            return failedFiles;
        } catch (Exception e) {
            log.error("批量删除文件失败: {}", e.getMessage(), e);
            throw new RuntimeException("批量删除文件失败", e);
        }
    }

    /**
     * 生成文件名
     * 格式：年月日_随机UUID_原始文件名
     *
     * @param originalFilename 原始文件名
     * @return 新文件名
     */
    private String generateFileName(String originalFilename) {
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");

        // 获取文件扩展名
        String extension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }

        return datePath + "/" + uuid + extension;
    }

    /**
     * 从URL中提取对象名称
     *
     * @param fileUrl 文件URL
     * @return 对象名称
     */
    private String extractObjectNameFromUrl(String fileUrl) {
        // 如果是完整URL
        if (fileUrl.startsWith("http")) {
            // 移除查询参数
            String url = fileUrl.contains("?") ? fileUrl.substring(0, fileUrl.indexOf("?")) : fileUrl;
            // 提取路径部分
            String path = url
                    .substring(url.indexOf(minioConfig.getBucketName()) + minioConfig.getBucketName().length() + 1);
            return path;
        }
        // 如果只是对象名称
        return fileUrl;
    }
}